use crate::config::DB;
use crate::controller::{error_response_json, render, success_response_json, AppState};
use crate::dto::LoginParams;
use crate::entity::User;
use crate::util::{
    self,
    rsa::{self, generate_key},
};
use crate::APP_STATE;
use captcha::{
    filters::{Dots, Noise, Wave},
    Captcha,
};
use hypers::prelude::*;
use rbs::to_value;

const AUTH_KEY: &str = "blog:auth_key";

pub struct Auth;

#[openapi(prefix = "admin", name = "auth", components(schemas(LoginParams)))]
impl Auth {
    #[get("/captcha", tag = "获取验证码")]
    async fn captcha(req: &mut Request) -> impl Responder {
        let mut c = Captcha::new();
        let c = c
            .add_chars(4)
            .apply_filter(Noise::new(0.4))
            .apply_filter(Wave::new(2.0, 20.0).horizontal())
            // .apply_filter(Wave::new(2.0, 20.0).vertical())
            .apply_filter(Dots::new(15))
            .view(260, 96);
        let mut res = Response::default();
        if let Some((data, png_data)) = c.as_tuple() {
            req.insert("auth_captcha", data);
            res.status(200).content_type("image/png").body(png_data);
            return res;
        }
        res.status(200).text("nodata");
        return res;
    }

    #[get("/login", tag = "登陆")]
    async fn login(req: &mut Request) -> impl Responder {
        let mut state = req.get::<AppState>(APP_STATE).unwrap();
        if let Ok((pri_key, pub_key)) = generate_key(1024) {
            let pub_key = pub_key
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "")
                .replace("\r\n", "")
                .replace("\r", "")
                .replace("\n", "")
                .replace(" ", "");
            state.ctx.insert("pub_key", &pub_key.trim());
            req.insert(AUTH_KEY, pri_key);
        }
        render(&state, "admin/auth/login.html")
    }

    #[post(
        "/login", 
        tag = "提交登陆",
        request_body(
            content = LoginParams,
            content_type = "application/x-www-form-urlencoded",
        ),
        responses(
            (status = 200, description = "登录", body = AuthBody),
        )
    )]
    async fn login_check(req: &mut Request) -> impl Responder {
        let params = req.parse_body::<LoginParams>().await.unwrap_or_default();
        println!("输入的参数 = {:?}",params);
        let login_id = req.get::<u32>("login_id").unwrap_or_default();
        if login_id > 0 {
            return error_response_json("你已经登陆了");
        }
        let auth_captcha = req.get::<String>("auth_captcha").unwrap_or_default();
        println!("输入的验证码 = {}",params.captcha.to_uppercase());
        println!("生成的验证码 = {}",auth_captcha.to_uppercase());
        if params.captcha.to_uppercase() != auth_captcha.to_uppercase() {
            return error_response_json("验证码错误");
        }
        let user = DB
            .query_decode::<User>(
                "select  * from user where  username = ?",
                vec![to_value!(&params.name)],
            )
            .await
            .unwrap_or_default();
        if user.id == 0 {
            return error_response_json("账号或者密码错误");
        }
        let pass = user.password.unwrap_or("".to_string());
        // 私钥
        let prikey = req.get::<String>(AUTH_KEY).unwrap_or_default();
        // 解出密码
        let params_pass = util::base64_decode(params.password.clone());
        let depass = rsa::decrypt(prikey.as_str(), params_pass.as_slice()).unwrap_or_default();
        let depass = String::from_utf8(depass).unwrap_or("".to_string());
        if !util::password_verify(depass.as_str(), &pass) {
            return error_response_json("账号或者密码错误");
        }
        let status = user.status.unwrap_or(0);
        if status == 0 {
            return error_response_json("账号不存在或者已被禁用");
        }
        req.insert("login_id", user.id);
        req.remove::<String>(AUTH_KEY);
        return success_response_json("登陆成功", "");
    }

    #[get("/logout")]
    async fn logout() -> impl Responder {}
}
